#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_push_back_actor.hpp>
#include <boost/bind.hpp>

#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <map>
#include <list>

using namespace std;
using namespace boost::spirit::classic;

std::string get_config_spec(){
    ifstream ifs("cfg_CI_BF_B5");
    if (!ifs){
        cerr << "Can't open the file cfg_CI_BF_B5" << endl;
        exit(1);
    }
    string line, total;
    while(getline(ifs, line)){
        line += "\n";
        total += line;
    }
    return total;
}

typedef rule<phrase_scanner_t> R;
typedef std::string Section;
typedef std::string ScName;
typedef std::string ScVersion;

typedef std::map<std::string, std::string> ScInfoMap;
typedef std::map<Section, ScInfoMap> SectionInfoMap;
typedef SectionInfoMap::const_iterator SECI;
typedef ScInfoMap::const_iterator SCCI;


struct ConfigGrammar: public grammar<ConfigGrammar>
{
    struct State
    {
        std::string version_, product_;
        ScName sc_name_;
        ScVersion sc_version_;
        Section section_;
        
        ScInfoMap sc_info_;
        SectionInfoMap section_info_;
        void newSection()
        {
            //cout << "Start section: " << section_ << std::endl;
            sc_info_.erase(sc_info_.begin(), sc_info_.end());
        }
        void finishSection()
        {
            //cout << "End section: " << section_ << std::endl;
            assert(section_ != "");
            section_info_[section_] = sc_info_;
            sc_info_.erase(sc_info_.begin(), sc_info_.end());
            section_ = "";
        }
        void finishSc()
        {
            assert(sc_name_ != "");
            sc_info_[sc_name_] = sc_version_;
        }
        
    }* state_;        
        
    template <typename ScannerT> struct definition
    {

        R version_string, product_string, version, product;
        R where, sc_name, sc_version, sc_info;
        R node, config_spec_parser;
        definition(const ConfigGrammar& self){
            using boost::bind;
            using boost::ref;
                    
            State& state_ = *self.state_;
            
            version_string = lexeme_d[str_p("LN") >> !str_p("T") >> *(alpha_p | digit_p | '_' |'.')];
            product_string = lexeme_d[*(alpha_p | digit_p | '_')];
    
            //config_spec grammer describtion
            version = str_p("version") >> version_string[assign_a(state_.version_)];
            product = str_p("product") >> product_string[assign_a(state_.product_)];
    
            where = lexeme_d[alpha_p >> *(alpha_p | digit_p | ':')];

            sc_name = lexeme_d[alpha_p >> *( (graph_p&(~str_p('<'))) | digit_p | '_' | '.' )];
            sc_version = lexeme_d[alpha_p >> *( (graph_p&(~str_p('<'))) | digit_p | '_' | '.' )];
    
            sc_info = sc_name[assign_a(state_.sc_name_)]
                >> sc_version[assign_a(state_.sc_version_)][bind(&State::finishSc, ref(state_))];
        
            node = ch_p('<') >> str_p("baselines") >> str_p("from")
                             >> where[assign_a(state_.section_)][bind(&State::newSection, ref(state_))] >> ch_p('>')
                             >> (*sc_info)
                             >> ch_p("<") >> ch_p('/') >>  str_p("baselines") >> ch_p(">")[bind(&State::finishSection, ref(state_))];

            config_spec_parser = version >> product >> *node >> end_p;
            
        }
        rule<ScannerT> const& start()const{
            return config_spec_parser;
        }
    };
    ConfigGrammar(State& state):state_(&state){}
};

    
int main(){

    
    //parse the cofnig_spec
    cout << "Input: " << endl;
    cout << get_config_spec();
    cout << "Input ended." << endl << endl;
    ConfigGrammar::State state;
    ConfigGrammar cg(state);
    parse_info<const char*> pi = parse(get_config_spec().c_str(), cg, space_p);

    if (pi.hit){
        if (pi.full){
            cout << "Success" << endl;
            SectionInfoMap& si = state.section_info_;
        
            for(SECI p = si.begin(); p != si.end(); ++p){
                cout << "Baselines from " << p->first << " : " << endl;
                const ScInfoMap& sim = p->second;
            
                for(SCCI i = sim.begin(); i != sim.end(); ++i)
                {
                    cout << i->first << '\t' << i->second << endl;
                }
            }
        }
        else{
            std::cout << "parsing data partially" << std::endl;
        }
        std::cout << pi.length << " characters parsed" << std::endl;
    }
    else{
        std::cout << "parsing failed; stopped at '" << pi.stop << "'" << std::endl; 
    }
    return 0;
}
